package com.demo.interpector;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.springframework.util.StreamUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.demo.annotation.MobileMethod;
import com.demo.mobile.DES;
import com.demo.mobile.MFrameEnumError;
import com.demo.mobile.MobException;
import com.demo.mobile.MobileInfo;
import com.demo.util.ClassUtils;
import com.demo.util.ProtobufUtils;
import com.google.gson.Gson;
import com.google.protobuf.ByteString;
import com.google.protobuf.GeneratedMessage;
import com.mdx.mobile.base.MRequest;
import com.mdx.mobile.base.Retn;
/**
 * 为mvc做登录过滤
 * @author Administrator
 *
 */
@SuppressWarnings("all")
public class MobileInterceptor implements HandlerInterceptor {
	
	private Logger logger = Logger.getLogger(MobileInterceptor.class);
	
	@Override
	public void afterCompletion(HttpServletRequest req,
			HttpServletResponse resp, Object handler, Exception arg3)
			throws Exception {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void postHandle(HttpServletRequest req, HttpServletResponse resp,
			Object handler, ModelAndView arg3) throws Exception {
		// TODO Auto-generated method stub
	}
	
	/**
	 * 为添加loginFilter的方法和controller验证是否登录
	 */
	@Override
	public boolean preHandle(HttpServletRequest req, HttpServletResponse resp,
			Object handler) throws Exception {
		boolean debug = "1".equals(req.getParameter("debug"));
		Retn.Msg_Retn.Builder returnBuilder = Retn.Msg_Retn.newBuilder();

	    GeneratedMessage.Builder requestMethodResult = null;
	    ServletOutputStream sos;
	    Map jsonShow;
	    if(!(handler instanceof HandlerMethod)){
	    	return true;
	    }
	    HandlerMethod method = (HandlerMethod)handler;
		
		//filter 不存在 验证method 是否存在loginFilter
		MobileMethod mobileMethod= method.getMethodAnnotation(MobileMethod.class);
		
		if(mobileMethod==null){//  不是手机接口 进入下一个chain
			return true;
		}
		
		try {
			//手机接口 进入单独处理
			//配置获取请求参数
			Map paramMap = getParam(req,mobileMethod);
			paramMap.remove("methodno");
			paramMap.remove("debug");
			
			//appid
//	    boolean hasAppId = false;
//		
//		if (hasAppId && StringUtils.isBlank((String) paramMap.get("appid"))) {
//			throw new MobException(MFrameEnumError.APPID_FAIL_ERROR);
//		}
			
			
			if (StringUtils.isBlank((String) paramMap.get("deviceid"))) {
				throw new MobException(MFrameEnumError.DEVICE_FAIL_ERROR);
			}
			
			//是否分页
			if (mobileMethod.isPage()){
				if (StringUtils.isBlank((String) paramMap.get("page"))) {
					throw new MobException(MFrameEnumError.PAGE_PARAM1_ERROR);
				}
				if (StringUtils.isBlank((String) paramMap.get("limit"))) {
					throw new MobException(MFrameEnumError.PAGE_PARAM2_ERROR);
				}
				Integer page = new Integer( (String)paramMap.get("page"));
				if(page>0){
					paramMap.put("page", page-1);
				}
			}
			
			
			//请求接口方法
			requestMethodResult = requestMethod(method.getMethod(), mobileMethod, paramMap);
			
			returnBuilder.setErrorCode(0);
			returnBuilder.setErrorMsg("");
			
			if ((!debug) && (requestMethodResult != null)) {
				returnBuilder.setRetnMessage(ByteString.copyFrom(ProtobufUtils.serialize(requestMethodResult)));
				returnBuilder.setReturnMethod(req.getRequestURI());
			}
		} catch (Exception e) {
			//异常处理
			Throwable rootThrowable = ExceptionUtils.getRootCause(e) == null ? e : ExceptionUtils.getRootCause(e);

			this.logger.error(rootThrowable.getMessage(), rootThrowable);

			if ((rootThrowable instanceof MobException)) {
				Integer errorCode = ((MobException) rootThrowable).getCode();
				returnBuilder.setErrorCode(errorCode == null ? 10000 : errorCode.intValue());
			} else {
				returnBuilder.setErrorCode(-1);
			}

			returnBuilder.setErrorMsg(rootThrowable.getMessage() == null ? String.valueOf(rootThrowable) : rootThrowable.getMessage());
			
			//mysql异常暂时无法解决
			if(returnBuilder.getErrorMsg().equals("Got an error writing communication packets")){
				returnBuilder.setErrorCode(0);
			}
		}finally{
			sos = resp.getOutputStream();
			try {
				if (!debug) {
					sos.write(new DES().desEncrypt(ProtobufUtils.serialize(returnBuilder)));
//					com.mdx.mobile.commons.data.Method.protobufSeralizeDes(returnBuilder, sos);
				} else {
					resp.setContentType("text/plain; charset=utf-8");
					resp.setCharacterEncoding("UTF-8");
					jsonShow = new HashMap();
					jsonShow.put("errorCode", Integer.valueOf(returnBuilder.getErrorCode()));
					jsonShow.put("errorMsg", returnBuilder.getErrorMsg());
					jsonShow.put("retnMessage", requestMethodResult);

					sos.write(new Gson().toJson(jsonShow).getBytes("UTF-8"));
				}
				sos.flush();
			} catch (Exception e) {
				this.logger.error(e.getMessage(), e);
			} finally {
				if (sos != null){
					sos.close();
				}
			}
	    }
		//拦截器结束 不进入方法
		return false;
	}
	
	
	
	private Map<String, Object> getParam(HttpServletRequest request,MobileMethod mobileMethod) throws Exception {
		Map paramMap = new HashMap();
		for (Object paramName : request.getParameterMap().keySet()) {
			if (!StringUtils.isNotBlank((String) paramName)){
				continue;
			}
			String paramValue = request.getParameter((String) paramName);

			paramMap.put(paramName, paramValue);
		}

		try {
			byte[] protobuf = {};
//			if(request instanceof StandardMultipartHttpServletRequest){
//				protobuf = StreamUtils.copyToByteArray(((StandardMultipartHttpServletRequest)request).getRequest().getInputStream());
////				MultipartFile f = ((StandardMultipartHttpServletRequest)request).getFile("file");
////				protobuf = f.getBytes();
//			}else{
//				protobuf = StreamUtils.copyToByteArray(request.getInputStream());
//			}
			protobuf = StreamUtils.copyToByteArray(request.getInputStream());
			MRequest.Msg_Request.Builder requestProtobuf = (MRequest.Msg_Request.Builder) ProtobufUtils.deserialize(
					new DES().desDecrypt(protobuf), MRequest.Msg_Request.class);

			for (int i = 0; i < requestProtobuf.getPostsCount(); i++) {
				paramMap.put(requestProtobuf.getPosts(i).getName(), requestProtobuf.getPosts(i).getValue());
			}

			if ((requestProtobuf.getRequestMessage() != null) && (requestProtobuf.getRequestMessage().size() > 0)) {
				if (mobileMethod != null) {
					Class requestClz = mobileMethod.reqClz();
					paramMap.put("requestProto", ProtobufUtils.deserialize(requestProtobuf.getRequestMessage(), requestClz));
					request.setAttribute("requestProto", ProtobufUtils.deserialize(requestProtobuf.getRequestMessage(), requestClz));
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		MobileInfo mobileInfo = new MobileInfo((String) paramMap.get("userid"), (String) paramMap.get("deviceid"),
				(String) paramMap.get("appid"),(String) paramMap.get("areaCode"));
		paramMap.put("mobileInfo", mobileInfo);
		paramMap.put("request", request);
		request.setAttribute("mobileInfo", mobileInfo);
		return paramMap;
	}
	
	
	private GeneratedMessage.Builder requestMethod(Method method, MobileMethod mobileMethod, Map<String, Object> paramMap)
			throws Exception {
		GeneratedMessage.Builder buildResult = null;

		Object methodResult = ClassUtils.invokeMethod(method.getDeclaringClass().getSimpleName(), method.getName(), paramMap);

		if (mobileMethod.respClz() != GeneratedMessage.class) {
			if (methodResult != null) {
				if ((methodResult instanceof GeneratedMessage.Builder))
					buildResult = (GeneratedMessage.Builder) methodResult;
				else {
					buildResult = ProtobufUtils.deserialize(methodResult, mobileMethod.respClz());
				}
			} else {
				Method responseNewmethod = mobileMethod.respClz().getMethod("newBuilder", new Class[0]);
				buildResult = (GeneratedMessage.Builder) responseNewmethod.invoke(mobileMethod.respClz(), new Object[0]);
			}
		}

		return buildResult;
	}

}
